Altering patterns in-place using SunVox DLL

pip install radiant-voices sunvox-dll-python jupyterlab
jupyter lab

This notebook shows you how to construct a simple SunVox project using Radiant Voices, load that project into the SunVox DLL, then alter the pattern data in-place while the project is playing in a SunVox-managed thread.

Imports


In [1]:
from random import choice
from time import sleep

from rv.api import Pattern, Project, m, NOTE, NOTECMD
from sunvox.api import init, Slot

Initialize SunVox


In [2]:
init(None, 44100, 2, 0)
slot = Slot()

Create a project with an Analog Generator


In [3]:
project = Project()
inst = project.output << project.new_module(
    m.AnalogGenerator,
    sustain=False,
    release=100,
)

Create a tiny 4×4 pattern


In [4]:
pattern = Pattern(lines=4)
project.attach_pattern(pattern)

Randomize the notes in the pattern


In [5]:
def randomize_notes(pdata, module):
    for row in pdata:
        for note in row:
            note.module = choice([0, module.index + 1])
            note.note = NOTECMD(choice(list(NOTE))) if note.module else NOTECMD.EMPTY

In [6]:
randomize_notes(pattern.data, inst)
pattern.data


Out[6]:
[[Note(note=<NOTECMD.C0: 1>, vel=0, module=2, ctl=0, val=0),
  Note(note=<NOTECMD.d2: 28>, vel=0, module=2, ctl=0, val=0),
  Note(note=<NOTECMD.d6: 76>, vel=0, module=2, ctl=0, val=0),
  Note(note=<NOTECMD.EMPTY: 0>, vel=0, module=0, ctl=0, val=0)],
 [Note(note=<NOTECMD.EMPTY: 0>, vel=0, module=0, ctl=0, val=0),
  Note(note=<NOTECMD.EMPTY: 0>, vel=0, module=0, ctl=0, val=0),
  Note(note=<NOTECMD.EMPTY: 0>, vel=0, module=0, ctl=0, val=0),
  Note(note=<NOTECMD.EMPTY: 0>, vel=0, module=0, ctl=0, val=0)],
 [Note(note=<NOTECMD.G3: 44>, vel=0, module=2, ctl=0, val=0),
  Note(note=<NOTECMD.EMPTY: 0>, vel=0, module=0, ctl=0, val=0),
  Note(note=<NOTECMD.E8: 101>, vel=0, module=2, ctl=0, val=0),
  Note(note=<NOTECMD.EMPTY: 0>, vel=0, module=0, ctl=0, val=0)],
 [Note(note=<NOTECMD.B3: 48>, vel=0, module=2, ctl=0, val=0),
  Note(note=<NOTECMD.EMPTY: 0>, vel=0, module=0, ctl=0, val=0),
  Note(note=<NOTECMD.F8: 102>, vel=0, module=2, ctl=0, val=0),
  Note(note=<NOTECMD.C3: 37>, vel=0, module=2, ctl=0, val=0)]]

Load & play the project


In [7]:
slot.load(project)
slot.play_from_beginning()


Out[7]:
0

Update pattern data in place during playback


In [8]:
def update_pdata(pdata, pattern):
    width = len(pattern.data[0])
    for y, line in enumerate(pattern.data):
        for x, note in enumerate(line):
            pnote = pdata[y * width + x]
            pnote.note = note.note
            pnote.vel = note.vel
            pnote.module = note.module
            pnote.ctl = note.ctl
            pnote.val = note.val

In [9]:
pdata = slot.get_pattern_data(0)

In [10]:
slot.play_from_beginning()
for _ in range(25):
    randomize_notes(pattern.data, inst)
    update_pdata(pdata, pattern)
    sleep(.5)
slot.stop()


Out[10]:
0